﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "LevelTriangleHeaderBehavior.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "IDocument.h"
#include "IElement.h"
#include "IElementBasicInformation.h"
#include "IGraphicsLine.h"
#include "IGraphicsText.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "Vector3dUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

DBOBJECT_DATA_DEFINE(LevelTriangleHeaderBehavior)
{
    m_pOwnerElement = nullptr;
    SetHeaderType__(LevelTriangleHeaderType::UpperHeader);
}

bool LevelTriangleHeaderBehavior::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    return true;
}
    
IElement* LevelTriangleHeaderBehavior::GetOwnerElement()
{
    return nullptr;
}
    
const IElement* LevelTriangleHeaderBehavior::GetOwnerElement() const
{
    return m_pOwnerElement;
}

NdbObject* LevelTriangleHeaderBehavior::GetTopOwnerObject() const
{
    return quick_cast<NdbObject>(m_pOwnerElement);
}

IDocument* LevelTriangleHeaderBehavior::GetDocument() const
{
    if (m_pOwnerElement)
    {
        return m_pOwnerElement->GetDocument();
    }

    return nullptr;
}

OwnerPtr<IGraphicsNodeGroup> LevelTriangleHeaderBehavior::CreateLevelHeader(const Vector3d& symbolPos, const Vector3d& symbolDir, const Vector3d& texDir, double height, double viewScale) const
{
    // 标头符号图形
    double symbolHeight = 300.0;    // 标头高度
    double symbolLength = 3000.0;   // 标头线长度
    double heightSpace = 100.0;    // 标头高度间距（与文字间距）
    double horizontalSpace = 150.0; // 标头水平间距（与文字间距）
    Vector3d symbolPnt1, symbolPnt2, symbolPnt3;
    Vector3d texBasePos;

    LevelTriangleHeaderType symbol = GetHeaderType();
    switch (symbol)
    {
    case LevelTriangleHeaderType::UpperHeader:
    {
        symbolPnt1 = symbolPos + Vector3d(0, 0, symbolHeight) - symbolDir * symbolHeight;
        texBasePos = symbolPnt1 + Vector3d(0, 0, heightSpace) + symbolDir * symbolLength;
        break;
    }
    case LevelTriangleHeaderType::LowerHeader:
    {
        symbolPnt1 = symbolPos - Vector3d(0, 0, symbolHeight) - symbolDir * symbolHeight;
        texBasePos = symbolPnt1 - Vector3d(0, 0, heightSpace) + symbolDir * symbolLength;
        break;
    }
    default:
    {
        return nullptr;
    }
    }
    symbolPnt2 = symbolPnt1 + symbolDir * symbolHeight * 2.0;
    symbolPnt3 = symbolPnt1 + symbolDir * symbolLength;

    OwnerPtr<IGraphicsNodeGroup> opSymbol = IGraphicsNodeGroup::Create();
    OwnerPtr<IGraphicsLine> line1 = IGraphicsLine::Create(symbolPos, symbolPnt1);
    OwnerPtr<IGraphicsLine> line2 = IGraphicsLine::Create(symbolPos, symbolPnt2);
    OwnerPtr<IGraphicsLine> line3 = IGraphicsLine::Create(symbolPnt1, symbolPnt3);
    opSymbol->AddChild(TransferOwnership(line1));
    opSymbol->AddChild(TransferOwnership(line2));
    opSymbol->AddChild(TransferOwnership(line3));

    // 标头文字
    double fontHeight = 3.6 / viewScale;
    Vector3d texNormal = texDir.Cross(Vector3d::UnitZ);
    bool isReverseLevel = MathUtils::IsEqual(Vector3dUtils::GetAngle(symbolDir, texDir), 0, Constants::DOUBLE_EPS) ? false : true;

    // 标高名称
    std::wstring levelName = GetOwnerElement()->GetBasicInformation()->GetName();
    Vector3d namePos = texBasePos + symbolDir * 150.0;
    OwnerPtr<IGraphicsText> pNameText = IGraphicsText::Create(L"", namePos, texDir, texNormal, (float)fontHeight, levelName.c_str(), AnchorAlignmentType::BottomCenter);
    if (isReverseLevel)
    {
        pNameText->SetAnchorAlignment(AnchorAlignmentType::RightBottom);
    }
    else
    {
        pNameText->SetAnchorAlignment(AnchorAlignmentType::LeftBottom);
    }
    opSymbol->AddChild(TransferOwnership(pNameText));

    // 将标高值转换为字符串
    std::wostringstream oss;
    oss.precision(3);
    oss.setf(std::ios::fixed); // 将浮点数的位数限定为小数点之后的位数
    oss << height;
    std::wstring wstrVal = oss.str();

    Vector3d heightPos = texBasePos;
    Vector3d signPos = texBasePos;
    // 正负零符号
    if (MathUtils::IsZero(height))
    {
        if (!isReverseLevel)
        {
            double signOffset = wstrVal.size() * fontHeight * 0.5 + 150.0;
            signPos = texBasePos - symbolDir * signOffset;
        }
        else
        {
            heightPos = namePos + texDir * (fontHeight + 150.0);
        }

        OwnerPtr<IGraphicsText> opSignText = CreateSignText(signPos, texDir, texNormal, viewScale, isReverseLevel);
        opSymbol->AddChild(TransferOwnership(opSignText));
    }

    // 标高高度
    OwnerPtr<IGraphicsText> opText = CreateElevationText(wstrVal, height, heightPos, texDir, texNormal, viewScale, isReverseLevel);
    opSymbol->AddChild(TransferOwnership(opText));

    return opSymbol;
}

OwnerPtr<IParameter> LevelTriangleHeaderBehavior::GetNativeParameter(int parameterId) const
{
    // 内建参数
    if (parameterId == PARAMETER_ID(LevelTriangleHeaderDirectionBuiltInParameter))
    {
        //OwnerPtr<IParameter> pParam = NEW_AS_OWNER_PTR(Parameter, GetDocument(),
            //ParameterStorageType::Int, false, false, true, 
            //PARAMETER_UID(LevelTriangleHeaderDirectionBuiltInParameter), 
            //ParameterProcessType::GeneralInput);
        ParameterAttributes pa = {false, false, true};
        OwnerPtr<IParameter> pParam = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Int,
            pa, PARAMETER_UID(LevelTriangleHeaderDirectionBuiltInParameter), 
            ParameterProcessType::GeneralInput);
        pParam->SetValueAsInt((int)GetHeaderType__());
        return TransferOwnership(pParam);
    }

    return nullptr;
}
    
bool LevelTriangleHeaderBehavior::SetNativeParameter(const IParameter *param, std::wstring* errorMessage)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMPLab",L"2024-03-30");
    // 内建参数
    if (param->GetParameterDefinitionId() == PARAMETER_ID(LevelTriangleHeaderDirectionBuiltInParameter))
    {
        SetHeaderType__((LevelTriangleHeaderType)param->GetValueAsInt());
        return true;
    }

    return false;
}

void LevelTriangleHeaderBehavior::ReportParameterDefinitions(std::vector<int>* parameterIds) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(parameterIds != nullptr, L"pParamDefUids为空",L"GDMPLab",L"2024-03-30");
    // 内建参数
    parameterIds->push_back(PARAMETER_ID(LevelTriangleHeaderDirectionBuiltInParameter));
}

bool LevelTriangleHeaderBehavior::IsParameterModifiable(int parameterId) const
{
    return true;
}

OwnerPtr<IGraphicsText> LevelTriangleHeaderBehavior::CreateElevationText(const std::wstring& heightTex, double height, const Vector3d& texPos, const Vector3d& texDir, const Vector3d& texNor, double viewScale, bool isViewLeft) const
{
    Vector3d heightTexPos = texPos;

    double fontHeight = 3.6 / viewScale;  //由于GText替换为GTextEx后会导致字形显示变大，此处为了基本达到原有的大小*0.735,5.0*0.735,此处的0.735为经验值
    OwnerPtr<IGraphicsText> opText = IGraphicsText::Create(L"", heightTexPos, texDir, texNor, (float)fontHeight, heightTex.c_str(), AnchorAlignmentType::BottomCenter);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opText, L"创建GraphicsText失败",L"GDMPLab",L"2024-03-30");

    LevelTriangleHeaderType symbol = GetHeaderType();
    switch (symbol)
    {
    case LevelTriangleHeaderType::UpperHeader:
    {
        if (isViewLeft)
            opText->SetAnchorAlignment(AnchorAlignmentType::LeftBottom);
        else
            opText->SetAnchorAlignment(AnchorAlignmentType::RightBottom);
        break;
    }
    case LevelTriangleHeaderType::LowerHeader:
    {
        if (isViewLeft)
            opText->SetAnchorAlignment(AnchorAlignmentType::LeftTop);
        else
            opText->SetAnchorAlignment(AnchorAlignmentType::RightTop);
        break;
    }
    default:
        DBG_WARN(L"请添加相应代码处理",L"GDMPLab",L"2024-03-30");
    }
    return opText;
}

OwnerPtr<IGraphicsText> LevelTriangleHeaderBehavior::CreateSignText(const Vector3d& signPos, const Vector3d& texDir, const Vector3d& texNor, double viewScale, bool isViewLeft) const
{
    double fontHeight = 3.6 / viewScale;
    OwnerPtr<IGraphicsText> opSignText = IGraphicsText::Create(L"", signPos, texDir, texNor, (float)fontHeight, L"±", AnchorAlignmentType::BottomCenter);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opSignText, L"创建GraphicsText失败",L"GDMPLab",L"2024-03-30");

    LevelTriangleHeaderType symbol = GetHeaderType();
    switch (symbol)
    {
    case LevelTriangleHeaderType::UpperHeader:
    {
        if (isViewLeft)
            opSignText->SetAnchorAlignment(AnchorAlignmentType::LeftBottom);
        else
            opSignText->SetAnchorAlignment(AnchorAlignmentType::RightBottom);
        break;
    }
    case LevelTriangleHeaderType::LowerHeader:
    {
        if (isViewLeft)
            opSignText->SetAnchorAlignment(AnchorAlignmentType::LeftTop);
        else
            opSignText->SetAnchorAlignment(AnchorAlignmentType::RightTop);
        break;
    }
    default:
        DBG_WARN(L"请添加相应代码处理",L"GDMPLab",L"2024-03-30");
        break;
    }
    return opSignText;
}

